package com.jmda.platform.commom;

import com.jmda.platform.constant.Constant;
import com.jmda.platform.database.DataSource;
import com.jmda.platform.plugs.context.JmdaContextInterface;
import com.jmda.platform.plugs.reference.DataReference;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.SearchAttribute;
import net.sf.ehcache.config.Searchable;
import net.sf.ehcache.search.Attribute;
import net.sf.ehcache.search.Query;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

public class LocalCacheManager {
    private static Long startTime = null;
    public static Map<String, String> jmdaPropertiesMap = null;

    private static Class<JmdaContextInterface> contextImpClass = null;

    private static Class<DataReference> dataReferenceImpClass = null;

    private static Class<DataSource> dataSourceImpClass = null;
    static {
        InputStream in = null;
        try {
            ClassPathResource cp = new ClassPathResource("/jmda-config/ehcache.xml");
            in = cp.getInputStream();
            CacheManager.create(in);
        } catch (CacheException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        jmdaPropertiesMap = new HashMap<String, String>();
        ClassPathResource cp = new ClassPathResource("jmda.properties");
        Properties properties = new OrderedProperties();
        try {
            properties.load(cp.getInputStream());
            for (Iterator its = properties.keySet().iterator(); its.hasNext(); ) {
                String zkey = (String) its.next();
                jmdaPropertiesMap.put(zkey, properties.getProperty(zkey).trim());
            }
        } catch (IOException e) {
            throw new RuntimeException("load jmda.properties error!");
        }

        System.out.println("JMDA 平台正在启动...");
        String buildVersion = Constant.Version;
        System.out.println("应用系统名称  :" + "模型驱动开发平台");
        System.out.println("内核编译版本  :" + buildVersion);
        startTime = System.currentTimeMillis();
        builtContext();
        builtDataReferenceImp();
        buildDataSourceImp();
    }

    private static void builtContext() {
        String contextImpClassPath = jmdaPropertiesMap.get("system.context.imp");
        if (contextImpClassPath != null && contextImpClassPath.trim().length() > 0) {
            try {
                Class<JmdaContextInterface> contextClass = (Class<JmdaContextInterface>) Class.forName(contextImpClassPath);
                JmdaContextInterface event = SpringContextUtil.getBean(contextClass);
                if (event != null) {
                    contextImpClass = contextClass;
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    private static void builtDataReferenceImp() {
        String dfImpClassPath = jmdaPropertiesMap.get("system.data.reference.imp");
        if (dfImpClassPath != null && dfImpClassPath.trim().length() > 0) {
            try {
                Class<DataReference> dfClass = (Class<DataReference>) Class.forName(dfImpClassPath);
                DataReference event = SpringContextUtil.getBean(dfClass);
                if (event != null) {
                    dataReferenceImpClass = dfClass;
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    private static void buildDataSourceImp() {
        String dataSourceImpClassPath = jmdaPropertiesMap.get("system.datasource.imp");
        if (dataSourceImpClassPath != null && dataSourceImpClassPath.trim().length() > 0) {
            try {
                Class<DataSource> dataSourceClass = (Class<DataSource>) Class.forName(dataSourceImpClassPath);
                DataSource event = SpringContextUtil.getBean(dataSourceClass);
                if (event != null) {
                	dataSourceImpClass = dataSourceClass;
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                //e.printStackTrace();
            	System.err.println("未找到自定义数据源配置类,jmda将读取默认数据源..");
                dataSourceImpClass = null;
            }
        }
    }
    public static String getContextJsParams() {
        if (contextImpClass != null) {
            JmdaContextInterface event = SpringContextUtil.getBean(contextImpClass);
            if (event != null) {
                Map<String, Object> params = event.getContextParams();
                StringBuffer jsParasm = new StringBuffer();
                for (String key : params.keySet()) {
                    jsParasm.append("var " + key + "='" + (String) params.get(key) + "';\n");
                }
                return "<script type=\"text/javascript\">\n" + jsParasm.toString() + "</script>";
            }
        }
        return "";
    }

    public static Map<String, Object> getContextParams() {
        if (contextImpClass != null) {
            JmdaContextInterface event = SpringContextUtil.getBean(contextImpClass);
            if (event != null) {
                Map<String, Object> params = event.getContextParams();
                if (params != null) {
                    return params;
                }
            }
        }
        return new HashMap<String, Object>();
    }

    public static String referenceData(String type, String value, String params) {
        DataReference event = SpringContextUtil.getBean(dataReferenceImpClass);
        if (event != null) {
            return event.referenceData(type, value, params);
        }
        return value;
    }
    public static DataSource setReadDataSource() {
    	if(dataSourceImpClass!=null){
        	DataSource event = SpringContextUtil.getBean(dataSourceImpClass);
            if (event != null) {
            	event.setReadDataSource();
                return event;
            }
    	}
        return null;
    }

    public static Long getStartTime() {
        return startTime;
    }

    public static Cache registCache(@SuppressWarnings("rawtypes") Class className, String[] searchAttributes) {
        CacheManager cacheManager = CacheManager.getInstance();
        cacheManager.removeCache(className.getName());
        CacheConfiguration cacheConfig = new CacheConfiguration(className.getName(), 99999).eternal(true);
        if (searchAttributes != null && searchAttributes.length > 0) {
            Searchable searchable = new Searchable();
            for (int i = 0; i < searchAttributes.length; i++) {
                if (searchAttributes[i] != null && searchAttributes[i].length() > 0) {
                    searchable.addSearchAttribute(new SearchAttribute().name(searchAttributes[i]));
                }
            }
            cacheConfig.addSearchable(searchable);
        }

        Cache cache = new Cache(cacheConfig);
        cacheManager.addCache(cache);
        return cache;
    }

    @SuppressWarnings("rawtypes")
    public static Cache getCache(Class className) {
        String name = className.getName();
        return CacheManager.getInstance().getCache(name);
    }

    public static void addSearchAttribute(Cache cache, Query query, Object obj) {
        // 获得对象的类型
        Class classType = obj.getClass();
        // 获得对象的所有属性
        Field[] fields = classType.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            // 获取数组中对应的属性
            Field field = fields[i];
            String fieldName = field.getName();
            if (!fieldName.equals("serialVersionUID")) {
                String stringLetter = fieldName.substring(0, 1).toUpperCase();
                // 获得相应属性的getXXX和setXXX方法名称
                String getName = "get" + stringLetter + fieldName.substring(1);
                try {
                    Method getMethod = classType.getMethod(getName, new Class[]{});
                    if (getMethod != null) {
                        Object value = getMethod.invoke(obj, new Object[]{});
                        if (value != null && (value instanceof String) && value != "") {
                            Attribute<String> key = cache.getSearchAttribute(fieldName);
                            query.addCriteria(key.eq(String.valueOf(value)));
                        }
                    }
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

class OrderedProperties extends Properties {

    private static final long serialVersionUID = -8219067822178277667L;

    private final LinkedHashSet<Object> keys = new LinkedHashSet<Object>();

    public Enumeration<Object> keys() {
        return Collections.<Object>enumeration(keys);
    }

    public Object put(Object key, Object value) {
        keys.add(key);
        return super.put(key, value);
    }

    public Set<Object> keySet() {
        return keys;
    }

    public Set<String> stringPropertyNames() {
        Set<String> set = new LinkedHashSet<String>();
        for (Object key : this.keys) {
            set.add((String) key);
        }
        return set;
    }

}
